package data;

import static org.lwjgl.opengl.GL11.GL_COMPILE;
import static org.lwjgl.opengl.GL11.GL_QUADS;
import static org.lwjgl.opengl.GL11.glBegin;
import static org.lwjgl.opengl.GL11.glEnd;
import static org.lwjgl.opengl.GL11.glEndList;
import static org.lwjgl.opengl.GL11.glGenLists;
import static org.lwjgl.opengl.GL11.glNewList;
import static org.lwjgl.opengl.GL11.glTexCoord2f;
import static org.lwjgl.opengl.GL11.glVertex2i;

import java.io.Serializable;

import org.newdawn.slick.opengl.Texture;

import application.Configuration;

/**
 * 
 * @author Drahomir Karchnak, Tomas Zima
 */
public class DataManager implements Serializable
{
	/**
	 * Constructor.
	 * It's private, because this class uses a singleton pattern.
	 */
	private DataManager()
	{
		generateBlocks();
		blocks = TextureLoader.loadTexture("blocks");
		menuBackgroundQuad = TextureLoader.loadTexture("menuBackground");
		//Binding blocks(texture) for using it
		blocks.bind();
	}
	
	/**
	 * Returns instance of running DataManager.
	 * 
	 * @return
	 */
	public static DataManager getInstance()
	{
		if (instance == null)
		{
			instance = new DataManager();
		}
		
		return instance;
	}
	
	/**
	 * Rebind texture with blocks.
	 */
	public void rebindBlocks()
	{
		blocks.bind();
	}
	
	/**
	 * Rebind texture for Menu background quads
	 */
	public void rebindMenuBackgroundQuad()
	{
		menuBackgroundQuad.bind();
	}
	
	/**
	 * Pregenerate all blocks used in the game.
	 */
	public void generateBlocks()
	{
		/**
		 * Generate rectangle with defined size on coordinates [0; 0]
		 * 
		 * @author Tomas Zima, Drahomir Karchnak
		 */
		class GenRectangle implements Serializable
		{
			GenRectangle(int size, int id)
			{
				int y = id / 8;
				int x = id % 8;
				
				glBegin(GL_QUADS);
					glTexCoord2f(x * (size / 256.0f), y * (size / 256.0f));
					glVertex2i(0, 0);
					
					glTexCoord2f(x * (size / 256.0f) + size / 256.0f, y * (size / 256.0f));
					glVertex2i(size, 0);
					
					glTexCoord2f(x * (size / 256.0f) + size / 256.0f,y * (size / 256.0f) + size / 256.0f);
					glVertex2i(size, size);
					
					glTexCoord2f(x * (size / 256.0f),y * (size / 256.0f) + size / 256.0f);
					glVertex2i(0, size);
				glEnd();
			}
		}
		
		// Allocate memory for identifiers of blocks
		displayListBlocks = new int[BlockType.values().length];
		
		// Generate display lists (identifiers)
		for (int i = 0; i < displayListBlocks.length; i++)
		{
			displayListBlocks[i] = glGenLists(1);
		}
		
		// Create display lists
		for (int i = 0; i < BlockType.values().length; i++)
		{
			glNewList(displayListBlocks[BlockType.values()[i].ordinal()], GL_COMPILE);
				new GenRectangle(Configuration.BLOCK_SIZE, i);
			glEndList();
		}
	}
	
	/**
	 * Pregenerate all possible backgrounds of blocks.
	 */
	public void generateBlockBackgrounds()
	{
		//
	}
	
	/**
	 * Returns display list identifier.
	 * 
	 * @param type
	 * @return
	 */
	public int getDisplayListID(BlockType type)
	{
		return displayListBlocks[type.ordinal()];
	}
	
	/*
	 * Be careful when changing this!
	 * Loading of textures depends on order (values) of
	 * these constants.
	 */
	public static enum BlockType implements Serializable
	{
		// Blocks
		BLOCK_STONE,
		BLOCK_STONE_BREAK,
		BLOCK_DIRT,
		BLOCK_DIRT_BREAK,
		BLOCK_GRASS,
		BLOCK_GRASS_BREAK,
		BLOCK_SAND,
		BLOCK_SAND_BREAK,
		BLOCK_COAL,
		BLOCK_COAL_BREAK,
		BLOCK_IRON,
		BLOCK_IRON_BREAK,
		BLOCK_GOLD,
		BLOCK_GOLD_BREAK,
		BLOCK_DIAMOND,
		BLOCK_DIAMOND_BREAK,
		BLOCK_TREE_BOTTOM,
		BLOCK_TREE_BOTTOM_BREAK,
		BLOCK_TREE_MIDDLE,
		BLOCK_TREE_MIDDLE_BREAK,
		BLOCK_TREE_MIDDLE_LEFT,
		BLOCK_TREE_MIDDLE_LEFT_BREAK,
		BLOCK_TREE_MIDDLE_RIGHT,
		BLOCK_TREE_MIDDLE_RIGHT_BREAK,
		BLOCK_CACTUS,
		BLOCK_CACTUS_BREAK,
		BLOCK_CACTUS_TOP,
		BLOCK_CACTUS_TOP_BREAK,
		BLOCK_TREE_LEAVES_LEFT,
		BLOCK_TREETOP_TOP_LEFT,
		BLOCK_TREETOP_TOP_MIDDLE,
		BLOCK_TREETOP_TOP_RIGHT,
		BLOCK_SAMPLING,
		BLOCK_SHROOM_RED,
		BLOCK_SHROOM_BROWN,
		BLOCK_FLOWER_YELLOW,
		BLOCK_TREE_LEAVES_RIGHT,
		BLOCK_TREETOP_MIDDLE_LEFT,
		BLOCK_TREETOP_MIDDLE_MIDDLE,
		BLOCK_TREETOP_MIDDLE_RIGHT,
		BLOCK_FLOWER_RED,
		//Backgrounds
		BACKGROUND_STONE,
		BACKGROUND_DIRT,
		BACKGROUND_GRASS,
		BACKGROUND_SAND,
		//blocks
		BLOCK_TREETOP_BOTTOM_LEFT,
		BLOCK_TREETOP_BOTTOM_MIDDLE,
		BLOCK_TREETOP_BOTTOM_RIGHT,
		
		// backgrounds
		BACKGROUND_HEAVEN,
		
		// blocks
		BLOCK_BEDROCK,
		
		// empty block
		BLOCK_NONE
	}
	
	private Texture	blocks;
	private Texture	menuBackgroundQuad;
	
	private static DataManager instance = null;
	
	private int displayListBlocks[];
	private int displayListBlocksBackground[];
}
